
class Position(object):
    #position类，主要作用：
    #根据信号更新当前的仓位
    #根据当前的数据，来更新账户的价值
    def __init__(self, order_instance):
        self.asset=order_instance.asset
        self.home_currency=order_instance.home_currency
        self.max_len=order_instance.max_len
        self.money=order_instance.money
        self.events=order_instance.events
        self.all_pair_name=order_instance.all_pair_name
        self.data_root=order_instance.data_root
        self.trade_pairs=order_instance.trade_pairs
        self.pairs=order_instance.pairs
        self.time_frame=order_instance.time_frame
        self.data_name=order_instance.data_name
        self.symbol_data=order_instance.symbol_data
        self.datas = order_instance.datas
        self.leverage=order_instance.leverage
        self.backtest=order_instance.backtest
        self.transmit=order_instance.transmit
        self.order_info=order_instance.order_info
        self.order_status=order_instance.order_status
        self.order_uncompleted=order_instance.order_uncompleted
        self.order_event_dict=order_instance.order_event_dict
        #用一个字典记录相应的交易状况
        self.trade_info={'time':[0],
                        'trade_id':[],
                        'position_info':{},
                        'value':[self.money],
                        'balance':[self.money],
                        'margin_used':[0],
                        'money_available':[self.money],
                        'unrealised_profit':[0],
                        'bar_ret':[0],
                        'bar_pnl':[0]}
        #绩效指标
        self.performance=[]

    def update_position_by_order(self):
        #更新当前的trade_position_dict
        #更新当前的trade_entry_price_dict
        #更新当前的trade_exit_price_dict
        #print('开始更新订单')
        key_list=self.order_event_dict.keys()
        #print('order',key_list)
        #print('self.money',self.money)
        #print('self.max_len',self.max_len)
        #assert 0>1
        margin_used=self.trade_info['margin_used'][-1]
        unrealised_profit=self.trade_info['unrealised_profit'][-1]
        balance=self.trade_info['balance'][-1]
        value=self.trade_info['value'][-1]
        print('value',value)
        print('balance',balance)
        print('unrealised_profit',unrealised_profit)
        print('margin_used',margin_used)
        assert isinstance(value,int)
        money_available=self.trade_info['money_available'][-1]
        bar_ret=0
        bar_pnl=0
        for key in key_list:
            event=self.order_event_dict[key]
            self.order_event_dict.pop(key)
            trade_id=event.order_id
            pair=event.pair
            size=event.size
            price=event.price
            time=event.time
            exectype=event.exectype
            margin=event.margin
            close_price=self.datas[pair]['close'][-1]
            pre_close_price=self.datas[pair]['close'][-2]
            #open_price=self.datas[pair].open[-1]
            #high_price=self.datas[pair].high[-1]
            #low_price=self.datas[pair].low[-1]
            side= 1 if event.side in ['buy'] else -1

            #开立仓位
            print('event.side',event.side)
            print('trade_info',self.trade_info.keys())
            if event.side in ['buy','sellshort']:
                self.trade_info['trade_id'].append(trade_id)
                self.trade_info['position_info'][trade_id]=[time,pair,side,size,price,margin]

                margin_used+=margin
                unrealised_profit_pair=self.convert_to_usd(pair,
                            side*(close_price-price)*size,exectype,'close')
                unrealised_profit+=unrealised_profit_pair
                print(6)
                print(value)
                print(unrealised_profit)
                value+=unrealised_profit
                print(7)
                money_available=value-margin_used
                bar_pnl=self.convert_to_usd(pair,
                            side*(close_price-price)*size,exectype,'close')

                bar_ret=bar_pnl/self.trade_info['balance'][-1]

            #平仓
            if event.side in ['sell','buy_to_cover']:
                close_trade_id_dict=self.close_position(side,size)
                for close_trade_id in close_trade_id_dict.keys():
                    if close_trade_id_dict[close_trade_id]=='all':
                        self.trade_info['trade_id'].remove(close_trade_id)
                        _,_,position_side,position_size,position_price,position_margin=self.trade_info['position_info'][close_trade_id]
                        margin_used-=position_margin
                        realised_profit=self.convert_to_usd(pair,
                                position_side*(price-position_price)*position_size,
                                exectype,'close')

                        unrealised_profit-=realised_profit
                        balance+=realised_profit
                        value=balance+unrealised_profit
                        money_available=value-margin_used
                        bar_pnl=self.convert_to_usd(pair,
                                position_side*(price-pre_close_price)*position_size,
                                exectype,'close')
                        bar_ret=bar_pnl/self.trade_info['balance'][-1]

                    if close_trade_id_dict[close_trade_id]=='partial':
                        #self.trade_info['order_id'].pop(close_trade_id)
                        _,_,position_side,position_size,position_price,position_margin=self.trade_info['position_info'][close_trade_id]
                        margin_used-=position_margin
                        realised_profit=self.convert_to_usd(pair,
                                position_side*(price-position_price)*size,
                                exectype,'close')

                        unrealised_profit-=realised_profit
                        balance+=realised_profit
                        value=balance+unrealised_profit
                        money_available-=margin_used
                        bar_pnl=self.convert_to_usd(pair,
                                position_side*(price-pre_close_price)*size,
                                exectype,'close')
                        bar_ret=bar_pnl/balance
                        self.trade_info['position_info'][close_trade_id][2]=position_size-size
        self.trade_info['value'].append(value)
        self.trade_info['balance'].append(balance)
        self.trade_info['margin_used'].append(margin_used)
        self.trade_info['money_available'].append(money_available)
        self.trade_info['unrealised_profit'].append(unrealised_profit)
        self.trade_info['bar_ret'].append(bar_ret)
        self.trade_info['bar_pnl'].append(bar_pnl)
        print('结束更新订单')

    def close_position(self,side,size,close_type='FF'):
        #close_type,分为先开先平(FF,first open,first close)，后开先平(LF,last open,first close)
        close_trade_id={}
        rest_close_size=size
        while rest_close_size>0:
            if close_type=='FF':
                trade_id_list=sorted(list(self.trade_info['position_info'].keys()))
                for i in trade_id_list:
                    _,_,position_side,position_size,_,_=self.trade_info['position_info'][i]
                    if position_side*side<0:
                        if position_size<rest_close_size:
                            rest_close_size-=position_size
                            close_trade_id[i]='all'
                        if position_size==rest_close_size:
                            rest_close_size=0
                            close_trade_id[i]='all'
                        if position_size>rest_close_size:
                            rest_close_size=0
                            close_trade_id[i]='partial'
                assert rest_close_size>0,'没有那么多的仓位可以平'
            if close_type=='LF':
                trade_id_list=sorted(list(self.trade_info['position_info'].keys()),reverse=True)
                for i in trade_id_list:
                    _,_,position_side,position_size,_,_=self.trade_info['position_info'][i]
                    if position_side*side<0:
                        if position_size<rest_close_size:
                            rest_close_size-=position_size
                            close_trade_id[i]='all'
                        if position_size==rest_close_size:
                            rest_close_size=0
                            close_trade_id[i]='all'
                        if position_size>rest_close_size:
                            rest_close_size=0
                            close_trade_id[i]='partial'
                assert rest_close_size>0,'没有那么多的仓位可以平'
        return close_trade_id


    def update_value_by_data(self):
        #print('开始更新账户价值数据')
        #更新position的相关价值
        margin_used=self.trade_info['margin_used'][-1]
        balance=self.trade_info['balance']
        unrealised_profit=0
        value=self.trade_info['value']
        money_available=self.trade_info['money_available']
        bar_pnl=self.trade_info['bar_pnl']
        bar_ret=self.trade_info['bar_ret']
        time=self.datas[list(self.datas.keys())[0]]['time'][-1]
        for trade_id in self.trade_info['trade_id']:
            _,pair,side,size,price,_=self.trade_info['position_info'][trade_id]
            close_price=self.datas[pair]['close'][-1]
            pre_close_price=self.datas[pair]['close'][-2]
            #open_price=self.datas[pair].open[-1]
            #high_price=self.datas[pair].high[-1]
            #low_price=self.datas[pair].low[-1]
            #self.trade_id_list.append(trade_id)
            unrealised_profit=unrealised_profit+self.convert_to_usd(pair,
                        side*(close_price-price)*size,'MARKET','close')
            value=balance+unrealised_profit
            money_available=value-margin_used
            bar_pnl+=self.convert_to_usd(pair,
                        side*(close_price-pre_close_price)*size,'MARKET','close')
            bar_ret=bar_pnl/balance

        self.trade_info['time'].append(time)
        self.trade_info['value'].append(value)
        self.trade_info['balance'].append(balance)
        self.trade_info['margin_used'].append(margin_used)
        self.trade_info['money_available'].append(money_available)
        self.trade_info['unrealised_profit'].append(unrealised_profit)
        self.trade_info['bar_ret'].append(bar_ret)
        self.trade_info['bar_pnl'].append(bar_pnl)
        #print('结束更新账户价值数据')

    def convert_to_usd(self,pair,value,exectype,price_type='close'):
        pair_symbol=pair.split('__')[0]
        time_frame=pair.split('__')[1]
        _,quote_currency=pair_symbol.split('_')
        quote_currency_usd=quote_currency+'_'+self.home_currency+'__'+time_frame
        usd_quote_currency=self.home_currency+'_'+quote_currency+'__'+time_frame
        if quote_currency==self.home_currency:
            value_usd=value
        elif quote_currency_usd in self.datas.keys():
            if exectype=='MARKET':
                rate=self.datas[quote_currency_usd][price_type][-1]
            if exectype=='LIMIT':
                rate=(self.datas[quote_currency_usd]['close'][-1]+
                    self.datas[quote_currency_usd]['open'][-1])/2
            value_usd=value*rate
        elif usd_quote_currency in self.datas.keys():
            if exectype=='MARKET':
                rate=self.datas[usd_quote_currency][price_type][-1]
            if exectype=='LIMIT':
                rate=(self.datas[usd_quote_currency]['close'][-1]+
                    self.datas[usd_quote_currency]['open'][-1])/2
            value_usd=value/rate
        return value_usd







    def update_performance(self, event):
        pass
